/** covenience header file for the codelets
 *
 * minimal openmp calls
 * Timer which calls omp_get_wtime
 * real-to-complex pointer casting function
 */
#ifndef BW_MAMBO_H
#define BW_MAMBO_H
#include <sys/time.h>
#include <complex>
//openmp stuff here
#if HAVE_OPENMP
#include <omp.h>
#else
typedef int omp_int_t;
inline omp_int_t omp_get_thread_num() { return 0;}
inline omp_int_t omp_get_max_threads() { return 1;}
#endif

/** casting real to complex pointer */
template<typename T>
inline std::complex<T>* complex_ptr(T* rptr)
{
  return reinterpret_cast<std::complex<T>*>(rptr);
}

#if defined(USE_OMP_WTIME)
/** definition of Timer */
struct Timer
{
  double start_time;
  inline Timer() { start_time=omp_get_wtime();}
  inline void restart() {start_time=omp_get_wtime();}
  inline double elapsed() const 
  {
    return omp_get_wtime()-start_time;
  }
};
#else
struct Timer
{
  /** lifted from G. Bauer example */
  typedef uint64_t ticks_t;
  __inline__ ticks_t getticks(void)
  {
    uint64_t x;
#if __WORDSIZE == 64
    asm volatile ("mftb %[x]" : [x] "=r" (x) );
#else
    uint32_t upper, lower, new_upper;
    do
    {
      asm volatile (
          "mftbu   %[Upper];"
          "mftb    %[Lower];"
          "mftbu   %[NewUpper];"

          : [Upper] "=r" (upper), [Lower] "=r" (lower), [NewUpper] "=r" (new_upper)
          :
          : "cr0"
          );
    } while (upper != new_upper);
    x = (((uint64_t) upper) << 32) | ((uint64_t) lower);
#endif
    return x;
  }

  ticks_t start_time;
  inline Timer() { restart();}
  inline void restart() 
  {
    start_time = getticks();
  }
  inline double elapsed() 
  {
    //using 512 HMz
    const double per_sec=1.953125e-9;
    return static_cast<double>((getticks()-start_time))*per_sec;
  }
};
//struct Timer
//{
//  struct timeval tp; 
//  double start_time;
//  inline Timer() { restart();}
//  inline void restart() 
//  {
//    gettimeofday(&tp, NULL);                                    
//    start_time=(double)tp.tv_sec+(1.e-6)*tp.tv_usec;
//  }
//  inline double elapsed() 
//  {
//    gettimeofday(&tp, NULL);                                    
//    return (double)tp.tv_sec+(1.e-6)*tp.tv_usec-start_time;
//  }
//};
#endif

#endif
